package com.mxpio.erp.plm.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.mxpio.erp.common.enums.CommonEnums;
import com.mxpio.erp.common.enums.OrderStatusEnums;
import com.mxpio.erp.common.enums.PlmEnums;
import com.mxpio.erp.common.plm.entity.*;
import com.mxpio.erp.common.plm.service.*;
import com.mxpio.erp.common.plm.vo.ProjectInfoDetailVO;
import com.mxpioframework.camunda.service.BpmnFlowService;
import com.mxpioframework.common.exception.MBootException;
import com.mxpioframework.common.vo.Result;
import com.mxpioframework.jpa.JpaUtil;
import com.mxpioframework.jpa.query.Criteria;
import com.mxpioframework.jpa.query.Operator;
import com.mxpioframework.security.service.impl.BaseServiceImpl;
import com.mxpioframework.security.util.SecurityUtils;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @Description: 项目恢复申请操作
 * @DATE: 2024-2-19
 * @Author: QB
 */
@Service
public class ProjectRecoveryOperationServiceImpl extends BaseServiceImpl<ProjectRecoveryOperation> implements ProjectRecoveryOperationService {
    @Autowired
    private ProjectInfoService projectInfoService;

    @Autowired
    private ProjectRecoveryOperationService projectRecoveryOperationService;

    @Autowired
    private ProjectInfoStatusHistoryService projectInfoStatusHistoryService;

    @Autowired
    private ProjectInfoCompleteService projectInfoCompleteService;

    @Autowired
    private ProjectInfoEndService projectInfoEndService;

    @Autowired
    private ProjectInfoChangeService projectInfoChangeService;

    @Autowired
    private ProjectPauseOperationService projectPauseOperationService;

    @Autowired
    private ProjectTaskService projectTaskService;

    @Autowired
    private BpmnFlowService bpmnFlowService;
    @Autowired
    private ProjectInfoRecordDraftService projectInfoRecordDraftService;
    @Autowired
    private ProjectDeliverableService projectDeliverableService;
    @Autowired
    private ProjectInfoRecordDeliverableDraftService projectInfoRecordDeliverableDraftService;

    /**
     * 恢复项目
     * @param recoveryOperation
     */
    @Override
    @Transactional
    public Result<?> recover(ProjectRecoveryOperation recoveryOperation) {
        ProjectRecoveryOperation operation = this.getById(ProjectRecoveryOperation.class, recoveryOperation.getBizNo());
        if (operation == null ) {//判断.实体类是否找到或者审核单是否通过
            return Result.error("项目暂停恢复操作表不存在或者审核单未通过,无法暂停");
        }
//        //检测当前项目是否存在未审核的恢复申请，若有，先完成审核
//        Criteria c = Criteria.create().addCriterion("proCode", Operator.EQ, operation.getProCode());
//        List<ProjectRecoveryOperation> list1 = this.list(ProjectRecoveryOperation.class, c);
//        for (ProjectRecoveryOperation projectRecoveryOperation : list1){
//            if (projectRecoveryOperation.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.CREATE.getStatusCode())||
//                    projectRecoveryOperation.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.AUDITING.getStatusCode())){
//                return Result.error("项目存在未审核的恢复申请,请先完成审核");
//            }
//        }

        ProjectInfo projectInfo = projectInfoService.getById(ProjectInfo.class, operation.getProCode());
        if (!projectInfo.getProStatus().equals(PlmEnums.ProStatus.PAUSE.getCode())){
            return Result.error("项目状态不是暂停状态,无法恢复");
        }
        //审批通过
        if (recoveryOperation.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode())){
            operation.setBpmnStatus(recoveryOperation.getBpmnStatus());
            operation.setIsAuditEnd(CommonEnums.YesNo.YES.getCode());
            this.update(operation);
        //查询暂停之前的状态,将项目状态恢复为立项或者进行中的状态
        Criteria criteria = Criteria.create().addCriterion("proCode", Operator.EQ, operation.getProCode());
        List<ProjectInfoStatusHistory> list = projectInfoStatusHistoryService.list(ProjectInfoStatusHistory.class, criteria);
        for (ProjectInfoStatusHistory projectInfoStatusHistory : list){
            if (projectInfoStatusHistory.getProStatusBefore().equals(PlmEnums.ProStatus.EXECUT.getCode())){//是否有执行中的状态
                projectInfo.setProStatus(projectInfoStatusHistory.getProStatusBefore());
                projectInfoService.update(projectInfo);
                break;
            }
        }
        //记录状态历史
        ProjectInfoStatusHistory history = new ProjectInfoStatusHistory();
        history.setProCode(projectInfo.getProCode());
        history.setProStatusBefore(PlmEnums.ProStatus.PAUSE.getCode());
        history.setProStatusAfter(projectInfo.getProStatus());
        history.setChangeTime(new Date());
        // 设置变更人，这就为恢复单申请人
        history.setChangeUser(operation.getApplyUser());
        // 设置备注信息，可以根据具体业务逻辑添加
        history.setRemark("项目恢复");
        projectInfoStatusHistoryService.save(history);

        //对项目对应的任务中的项目状态和项目名称进行更改
        Criteria c1 = Criteria.create().addCriterion("proCode", Operator.EQ, projectInfo.getProCode());
        List<ProjectTask> tasks = projectTaskService.list(ProjectTask.class, c1);
        for (ProjectTask projectTask : tasks){
            projectTask.setProStatus(projectInfo.getProStatus());
            projectTaskService.update(projectTask);
        }
        //审批未通过
        }else if (recoveryOperation.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.CLOSED.getStatusCode())){
            operation.setBpmnStatus("不同意");
            operation.setIsAuditEnd(CommonEnums.YesNo.YES.getCode());
            this.update(operation);
            return Result.OK("审批未通过，请重新提交");
        }
        return Result.OK(projectInfo);
    }

    /**
     * 添加恢复申请单
     *
     *
     */
    @Override
    @Transactional
    public Result<?> saveAll(String key, String loginUsername, String businessKey, Map<String, Object> properties) {
        String proCode =(String) properties.get("proCode");
//        String proCode = recoveryOperation.getProCode();
        Criteria criteria = Criteria.create().addCriterion("proCode", Operator.EQ, proCode);
        //
        ProjectInfo projectInfo = projectInfoService.getById(ProjectInfo.class, proCode);
        if (!projectInfo.getProStatus().equals(PlmEnums.ProStatus.PAUSE.getCode())){
            return Result.error("当前项目状态不是暂停状态，不能发起恢复申请");
        }

        //判断此时是否有其他的工作流在审核
        List<ProjectInfoChange> list1 = projectInfoChangeService.list(ProjectInfoChange.class, criteria);
        for (ProjectInfoChange projectInfoChange : list1){
            if (projectInfoChange.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.CREATE.getStatusCode())||
                    projectInfoChange.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.AUDITING.getStatusCode())){
                return Result.error("项目有变更工作流正在审核,不能恢复");
            }
        }
        List<ProjectInfoEnd> list2 = projectInfoEndService.list(ProjectInfoEnd.class, criteria);
        for (ProjectInfoEnd projectInfoEnd : list2){
            if (projectInfoEnd.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.CREATE.getStatusCode())||
                    projectInfoEnd.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.AUDITING.getStatusCode())){
                return Result.error("项目有终止工作流在审核中,不能恢复");
            }
        }
//        List<ProjectPauseOperation> list3 = projectPauseOperationService.list(ProjectPauseOperation.class, criteria);
//        for (ProjectPauseOperation pauseOperation : list3){
//            if (pauseOperation.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.CREATE.getStatusCode())||
//                    pauseOperation.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.AUDITING.getStatusCode())){
//                return Result.error("项目有暂停工作流在审核中,不能恢复");
//            }
//        }
        List<ProjectInfoComplete> list4 = projectInfoCompleteService.list(ProjectInfoComplete.class, criteria);
        for (ProjectInfoComplete projectInfoComplete : list4){
            if (projectInfoComplete.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.CREATE.getStatusCode())||
                    projectInfoComplete.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.AUDITING.getStatusCode())){
                return Result.error("项目有结项工作流在审核中,不能恢复");
            }
        }

        List<ProjectRecoveryOperation> list = this.list(ProjectRecoveryOperation.class, criteria);
        for (ProjectRecoveryOperation operation : list){
            if (operation.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.CREATE.getStatusCode())||
                    operation.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.AUDITING.getStatusCode())){
                return Result.error("存在正在审核的恢复申请单，请等待审核完成后再提交");
            }
        }
        ProjectRecoveryOperation recoveryOperation = new ProjectRecoveryOperation();
        recoveryOperation.setProCode(proCode);
        recoveryOperation.setBpmnStatus(OrderStatusEnums.BpmnStatus.CREATE.getStatusCode());
        recoveryOperation.setReason(properties.get("reason")!=null ?properties.get("reason").toString():null);
        recoveryOperation.setAttachment(properties.get("attachment")!=null ?properties.get("attachment").toString():null);
        recoveryOperation.setApplyUser(SecurityUtils.getLoginUsername());
        recoveryOperation.setApplyTime(new Date());
        this.save(recoveryOperation);
        String bizNo = recoveryOperation.getBizNo();
        properties.put("bizNo", bizNo);

        //将信息 存入草稿表
        ProjectInfoRecordDraft projectInfoRecordDraft = new ProjectInfoRecordDraft();
        BeanUtil.copyProperties(projectInfo, projectInfoRecordDraft);
        projectInfoRecordDraft.setBizNo(bizNo);
        projectInfoRecordDraftService.save(projectInfoRecordDraft);
        List<ProjectDeliverable> list6 = projectDeliverableService.list(ProjectDeliverable.class, Criteria.create().addCriterion("proCode", Operator.EQ, proCode));
        for (ProjectDeliverable projectDeliverable : list6){
            ProjectInfoRecordDeliverableDraft projectInfoRecordDeliverableDraft = new ProjectInfoRecordDeliverableDraft();
            BeanUtil.copyProperties(projectDeliverable, projectInfoRecordDeliverableDraft,"id");
            projectInfoRecordDeliverableDraft.setBizNo(bizNo);
            projectInfoRecordDeliverableDraftService.save(projectInfoRecordDeliverableDraft);
        }
        //发起工作流
        ProcessInstance processInstance = bpmnFlowService.startWithFormByKey(key, loginUsername, businessKey, properties);
        recoveryOperation.setProcessInstanceId(processInstance.getId());
        projectRecoveryOperationService.update(recoveryOperation);
        return Result.OK(recoveryOperation);
    }

    @Override
    @Transactional
    public ProjectRecoveryOperation getOne(String bizNo) {
        ProjectRecoveryOperation byId = this.getById(ProjectRecoveryOperation.class, bizNo);
//        List<ProjectRecoveryOperation> list = this.list(ProjectRecoveryOperation.class, Criteria.create().addCriterion("proCode", Operator.EQ, proCode));
//        for (ProjectRecoveryOperation recoveryOperation : list)
//            if (recoveryOperation.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.CREATE.getStatusCode())||recoveryOperation.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.AUDITING.getStatusCode())){
//                return recoveryOperation;
//            }
        return byId;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<?> getDetail(String bizNo) {
        ProjectInfoDetailVO projectInfoDetailVO = new ProjectInfoDetailVO();
        ProjectInfoRecordDraft infoRecordDraft = JpaUtil.linq(ProjectInfoRecordDraft.class).equal("bizNo", bizNo).findOne();
        List<ProjectInfoRecordDeliverableDraft> deliverableDrafts = projectInfoRecordDeliverableDraftService.list(ProjectInfoRecordDeliverableDraft.class, Criteria.create().addCriterion("bizNo", Operator.EQ, bizNo));
        ProjectRecoveryOperation byId = this.getById(ProjectRecoveryOperation.class, bizNo);
        projectInfoDetailVO.setProjectRecoveryOperation(byId);
        projectInfoDetailVO.setProjectInfoRecordDraft(infoRecordDraft);
        projectInfoDetailVO.setProjectInfoRecordDeliverableDrafts(deliverableDrafts);
        return Result.OK(projectInfoDetailVO);
    }
}
